27 再论智能指针(上)
再论智能指针
-
思考
使用智能指针(SmartPointer)替换单链表(LinkList)中的原生指针是否可行?
-
问题出在哪里?
- SmartPointer的设计方案
- 指针生命周期结束时主动释放堆空间
- 一片堆空间最多只能由一个指针标识
- 杜绝指针运算和指针比较
- SmartPointer的设计方案
-
新的设计方案 是时候创建新的智能指针了!
- 新的设计方案
- Pointer是智能指针的抽象父类(模板)
- 纯虚析构函数 virtual ~Pointer() = 0;(Pointer需要被继承才能产生可用类)
- 重载operator -> ()
- 重载operator * ()
template<typename T>
class Pointer:public Object
{
public:
Pointer(T *p = nullptr);
T* operator -> ();
T& operator * ();
bool isNull();
T* get();
protected:
T* m_pointer;
}; - Pointer是智能指针的抽象父类(模板)
编程实验
-
智能指针的新方案
//Pointer
#ifndef POINTER_H
#define POINTER_H
#include "Object.h"
namespace KylinLib {
template<typename T>
class Pointer : public Object{
public:
T* get() const{
return m_pointer;
}
T& operator *() const{
return *m_pointer;
}
T* operator ->() const{
return m_pointer;
}
bool isNull() const{
return (m_pointer==nullptr);
}
virtual ~Pointer() = 0;
protected:
T *m_pointer = nullptr;
};
}
#endif // POINTER_H//SmartPointer.h
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#include "Pointer.h"
namespace KylinLib {
template<typename T>
class SmartPointer : public Pointer<T>
{
public:
SmartPointer(T *p){
this->m_pointer = p;
}
SmartPointer(const SmartPointer &p){
this->m_pointer = p.m_pointer;
const_cast<SmartPointer<T>&>(p).m_pointer = nullptr;
}
~SmartPointer(){
delete this->m_pointer;
}
SmartPointer& operator=(const SmartPointer &p){
if(this!=&p){
if(this->m_pointer!=nullptr) delete this->m_pointer;
const_cast<SmartPointer<T>&>(p).m_pointer = nullptr;
p.m_pointer = nullptr;
}
return *this;
}
};
}
#endif // SMARTPOINTER_H
思考:如何实现SharedPointer使得多个智能指针对象可以指向同一片堆内存,同时支持堆内存的自动释放?
28 再论智能指针(下)
再论智能指针
- 课程目标
- 完成
SharedPointer
类的具体实现
- 完成
- SharedPointer设计要点
- 类模板
- 通过计数机制(ref)标识堆内存
- 堆内存被指向时:ref++
- 指针被置空时:ref--
- ref==0时:释放堆空间
- 通过计数机制(ref)标识堆内存
- 类模板
- 计数机制原理剖析
-
SharedPointer类的声明
template<typename T>
class SharedPointer : public Pointer<T>
{
public:
SharedPointer(T *p = nullptr);
SharedPointer(const SharedPointer<T>& obj);
SharedPointer<T>& operator= (SharedPointer<T> &obj);
void clear(); //将当前指针置为空
~SharedPointer();
protected:
int *m_ref; //计数机制成员指针
} -
智能指针的比较 由于SharedPointer支持多个对象同时指向一片堆空间;因此,必须支持比较操作!
编程实验
-
智能指针的新成员
//SharedPointer.h
#ifndef SHAREDPOINTER_H
#define SHAREDPOINTER_H
#include "Pointer.h"
namespace KylinLib {
template<typename T>
class SharedPointer : public Pointer<T>{
public:
SharedPointer(T *p){
if(p==nullptr) return;
this->m_pointer = p;
m_counter = new size_t(1);
}
SharedPointer(const SharedPointer &obj){
if(obj.m_counter==nullptr) return;
this->m_counter = obj.m_counter;
this->m_pointer = obj.m_pointer;
(*m_counter)++;
}
SharedPointer& operator=(const SharedPointer &obj){
if(this!=&obj){
clear();
this->m_counter = obj.m_counter;
this->m_pointer = obj.m_pointer;
(*m_counter)++;
}
}
void clear(){
if(m_counter==nullptr) return;
(*m_counter)--;
if(*m_counter == 0){
delete m_counter;
delete this->m_pointer;
}
this->m_pointer = nullptr;
m_counter = nullptr;
}
// bool operator==(const SharedPointer &obj){
// return (this->m_pointer==obj.m_pointer);
// }
~SharedPointer(){
clear();
}
private:
size_t *m_counter = nullptr;
};
template <typename T>
bool operator== (const SharedPointer<T> l,const SharedPointer<T> r){
return (l.get()==r.get());
}
template <typename T>
bool operator!= (const SharedPointer<T> l,const SharedPointer<T> r){
return !(l==r);
}
}
#endif // SHAREDPOINTER_H -
智能指针的使用军规
- 只能用来指向堆空间的单个变量(对象)
- 不同类型的智能指针对象不能混合使用
- 不要使用delete释放智能指针指向的堆空间
小结
- SharedPointer最大程度的模拟了原生指针的行为
- 计数机制确保多个智能指针合法的指向同一片堆空间
- 智能指针只能用于指向堆空间中的内存
- 不同类型的智能指针不要混合使用
- 堆对象的生命周期由智能指针进行管理
练习:用SharedPointer替换LinkedList中的原生指针。
思考:在KylinLib内部是否需要使用智能指针?为什么?